package com.qingyun.shop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qingyun.common.core.mybatisplus.core.ServicePlusImpl;
import com.qingyun.common.core.page.TableDataInfo;
import com.qingyun.common.core.redis.RedisCache;
import com.qingyun.common.exception.ServiceException;
import com.qingyun.common.utils.PageUtils;
import com.qingyun.security.utils.SecurityUtils;
import com.qingyun.shop.domain.TiktokBankCard;
import com.qingyun.shop.domain.TiktokWithdrawApply;
import com.qingyun.shop.domain.bo.shop.*;
import com.qingyun.shop.domain.vo.TiktokBankCardExcelVo;
import com.qingyun.shop.domain.vo.TiktokBankCardListVo;
import com.qingyun.shop.domain.vo.TiktokBankCardVo;
import com.qingyun.shop.mapper.TiktokBankCardMapper;
import com.qingyun.shop.mapper.TiktokWithdrawApplyMapper;
import com.qingyun.shop.service.ITiktokBankCardService;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 商户银行卡信息Service业务层处理
 *
 * @author qingyun
 * @date 2021-10-19
 */
@Service
@AllArgsConstructor
public class TiktokBankCardServiceImpl extends ServicePlusImpl<TiktokBankCardMapper, TiktokBankCard, TiktokBankCardVo> implements ITiktokBankCardService {

    private final MapperFacade mapperFacade;

    private final RedisCache redisCache;

    private final TiktokWithdrawApplyMapper withdrawApplyMapper;

    @Override
    public TiktokBankCardVo queryById(Long id){
        return getVoById(id);
    }

    @Override
    public TableDataInfo<TiktokBankCardListVo> queryPageList(TiktokBankCardQueryBo bo) {
    	if(SecurityUtils.isProxy()){
    		bo.setProxyId(SecurityUtils.getProxy().getId());
		}
        Page<TiktokBankCardListVo> result = baseMapper.selectBankCardList(PageUtils.buildPage(), bo);
        result.getRecords().forEach(b -> {
            // 脱敏
            b.setBankNumber(DesensitizedUtil.bankCard(b.getBankNumber()));
            b.setIdCard(DesensitizedUtil.desensitized(b.getIdCard(), DesensitizedUtil.DesensitizedType.ID_CARD));
        });
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<TiktokBankCardExcelVo> queryList(TiktokBankCardQueryBo bo) {
        return baseMapper.selectBankCardExcelList(bo);
    }

    private LambdaQueryWrapper<TiktokBankCard> buildQueryWrapper(TiktokBankCardBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TiktokBankCard> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getBankNumber()), TiktokBankCard::getBankNumber, bo.getBankNumber());
        lqw.eq(StringUtils.isNotBlank(bo.getBankDeposit()), TiktokBankCard::getBankDeposit, bo.getBankDeposit());
        lqw.like(StringUtils.isNotBlank(bo.getBranchName()), TiktokBankCard::getBranchName, bo.getBranchName());
        lqw.eq(StringUtils.isNotBlank(bo.getBankPhone()), TiktokBankCard::getBankPhone, bo.getBankPhone());
        lqw.eq(bo.getProxyId() != null, TiktokBankCard::getProxyId, bo.getProxyId());
        lqw.eq(bo.getStatus() != null, TiktokBankCard::getStatus, bo.getStatus());
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(TiktokBankCardAddBo bo) {
        TiktokBankCard add = BeanUtil.toBean(bo, TiktokBankCard.class);

        if (SecurityUtils.isManager() && bo.getProxyId() == null) {
            throw new ServiceException("管理创建，代理商id必传");
        }

        if (bo.getProxyId() == null) {
            add.setProxyId(SecurityUtils.getProxy().getId());
        }

        Integer count = baseMapper.selectCount(Wrappers.query(new TiktokBankCard().setProxyId(bo.getProxyId())));
        if (count > 3) {
            throw new ServiceException("您已经创建了三张银行卡，不能继续创建了", HttpStatus.HTTP_BAD_REQUEST);
        }

        validEntityBeforeSave(add);
        return save(add);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(TiktokBankCardEditBo bo) {
        TiktokBankCard update = BeanUtil.toBean(bo, TiktokBankCard.class);
//        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(TiktokBankCard entity){
        //TODO 做一些数据校验,如唯一约束

        Integer count = baseMapper.selectCount(Wrappers.query(new TiktokBankCard().setProxyId(entity.getProxyId()).setBankNumber(entity.getBankNumber())));
        if (count > 0) {
            throw new ServiceException("添加失败，银行卡号已存在", HttpStatus.HTTP_BAD_REQUEST);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        Long proxyId = SecurityUtils.getProxy().getId();
        ids.forEach(id -> {
            Integer count = withdrawApplyMapper.selectCount(Wrappers.query(new TiktokWithdrawApply().setProxyId(proxyId).setBankId(id).setStatus(0)));
            if (count > 0) {
                throw new ServiceException("删除失败，当前银行卡有提现受理。");
            }
        });

        return removeByIds(ids);
    }

    @Override
    public List<TiktokBankCardVo> queryByProxyId(Long proxyId) {
        List<TiktokBankCard> tiktokBankCards = baseMapper.selectList(Wrappers.query(new TiktokBankCard().setProxyId(proxyId)));

        tiktokBankCards.forEach(b -> b.setBankNumber(DesensitizedUtil.bankCard(b.getBankNumber())));

        return mapperFacade.mapAsList(tiktokBankCards, TiktokBankCardVo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editStatus(Long id, Integer status) {
        TiktokBankCard tiktokBankCard = new TiktokBankCard();
        tiktokBankCard.setId(id);
        tiktokBankCard.setStatus(status);

        return baseMapper.updateById(tiktokBankCard) > 0;
    }

    /**
     * 银行卡三要素校验
     *
     * @param checkBo
     */
    @Override
    public Boolean realCheck(BankCardRealCheckBo checkBo) {
        // 先从缓存里拿
        Boolean cache = redisCache.getCacheObject(checkBo.getRealName() + checkBo.getIdCard() + checkBo.getBankNumber());
        if (cache != null) {
            return cache;
        }
        //接口地址
        String myPostUrl = "http://api.chinadatapay.com/communication/personal/1886";
        //请求参数
        Map< String, Object> params = new HashMap<>();
        //输入数据宝提供的 key
        params.put("key", "");
        //姓名
        params.put("name", checkBo.getRealName());
        //身份证号
        params.put("idcard", checkBo.getIdCard());
        //银行卡号
        params.put("acct_no", checkBo.getBankNumber());

        String result;
        try {
            result = post(myPostUrl, params);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("验证失败，请联系平台负责人");
        }
        JSONObject resultJson = null;
        if (result != null && !result.equals("")) {
            resultJson = JSONObject.parseObject(result);
        }
        if (resultJson.getString("code").equals("10000")) {
            JSONObject data = resultJson.getJSONObject("data");
            // 1 验证一致 2 不一致 3 异常情况
            if (ObjectUtil.isNotNull(data)&&data.get("state").equals("1")) {
                // 存入缓存
                redisCache.setCacheObject(checkBo.getRealName() + checkBo.getIdCard() + checkBo.getBankNumber(),
                        Boolean.TRUE,
                        1,
                        TimeUnit.MINUTES);
                return Boolean.TRUE;
            } else {
				throw new ServiceException(resultJson.getString("message"));
            }
        }else{
        	throw new ServiceException(resultJson.getString("message"));
		}
    }

    private static String post(String url, Map< String, Object> params) throws Exception {
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        return PostHttpRequest(url, pairs);
    }
    private static String PostHttpRequest(String Url, List< NameValuePair> params) throws Exception {
        CloseableHttpClient client = HttpClients.createDefault();
        //超时时间
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(300000).setConnectTimeout(300000).build();
        String result = null;
        try{
            HttpPost request = new HttpPost(Url);
            request.setConfig(requestConfig);
            request.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            HttpResponse respones = client.execute(request);
            if (respones.getStatusLine().getStatusCode() == 200) {
                result = EntityUtils.toString(respones.getEntity(), "UTF-8");
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            client.close();
        }
        return result;
    }
    private static ArrayList<NameValuePair> covertParams2NVPS(Map< String, Object> params) {
        ArrayList< NameValuePair> pairs = new ArrayList<>();
        if (params == null || params.size() == 0) {
            return pairs;
        }
        for (Map.Entry< String, Object> param : params.entrySet()) {
            Object value = param.getValue();
            if  (value instanceof String[]) {
                String[] values = (String[]) value;
                for(String v : values) {
                    pairs.add(new BasicNameValuePair(param.getKey(), v));
                }
            }else {
                if (value instanceof Integer) {
                    value = Integer.toString((Integer) value);
                } else if (value instanceof Long) {
                    value = Long.toString((Long) value);
                }
                pairs.add(new BasicNameValuePair(param.getKey(), (String) value));
            }
        }
        return pairs;
    }
}
